#ifndef __CE_SCENE_NODE_H__
#define __CE_SCENE_NODE_H__


#include <export.h>
#include <asset/asset.h>
#include <scene/enum.h>
#include <math/boundingbox.h>
#include <list>
#include <string>
#include <vector>

struct iAnimator;
struct iDevice;
class ceGroupNode;
class ceLight;
struct ceRenderEnvironment;
class ceSector;

class ceNode;
typedef ceNode* NodePtr;
typedef std::list<NodePtr> NodeList;
typedef std::list<NodePtr>::iterator NodeListIterator;
typedef std::vector<NodePtr> NodeVector;
typedef std::vector<NodePtr>::iterator NodeVectorIterator;

/**
 * \addtogroup scene
 * @{
 */

/**
 * @brief Scene node with a bounding box contained within a ceGroupNode
 */
class CE_API ceNode : public ceAsset
{
  CE_OBJECT
	CE_ASSET_ID4('n', 'o', 'd', 'e')
  friend class ceGroupNode;
private:
  /**
   * \name Building the hirarchie
   * @{
   */

  /**
   * @brief The parent node
   *
   * @see GetParent()
   */
  ceNode            *_parent;

  /**
   * @brief All child nodes of this node
   *
   * @see AddNode(), RemoveNode();
   */
  NodeVector        _children;

  /**
   * @brief The sector the node is located in.
   */
  ceSector*         _sector;

  /**
   * @}
   */

  /**
   * \name Transformation
   * @{
   */

  /**
   * @brief The local matrix, relative to the parent
   */
  ceMatrix4f      _localMatrix;

  ceMatrix4f      _localMatrixInverted;

  /**
   * @brief The global matrix, relative to the world
   */
  ceMatrix4f      _globalMatrix;

  ceMatrix4f      _globalMatrixInverted;

  bool            _inversionDirty;

  /**
   * @}
   */

  iAnimator*                  _animator;

  /**
   * @brief _boundingBox
   */

  ceBoundingBox   _boundingBox;

  /**
   * \brief Whether or not this node should be clipped.
   *
   * Nodes that not get clipped will be rendered no matter they are visible
   * or not. The default value is \a true.
   */
  bool                _clip;



  void FinishTransformationPrivate ();

  void UpdateParentBoundingBox ();
  void UpdateBoundingBox ();

protected:

  inline virtual void FillPrivateBoundingBox (ceBoundingBox& bbox) { }
  inline virtual void UpdateTransformation () { }


public:
  ceNode ();
  virtual ~ceNode ();
  virtual ceNodeType GetNodeType () const;

  /**
   * \name Hierarchie
   * @{
   */
  void SetSector (ceSector* sector);
  ceSector* GetSector ();
  const ceSector* GetSector () const;


  const ceNode* GetParent () const;
  ceNode* GetParent ();

  void AddNode (ceNode* node);
  bool RemoveNode (const ceNode *node, bool testchildren = true);
  inline size_t GetNumberOfChildren () { return _children.size(); }
  inline ceNode* GetChild (size_t idx) { return _children[idx]; }

  /**
   * @}
   */

  /**
   * \name Transformation
   * @{
   */

  void ClearTransformation ();

  void SetMatrix (const ceMatrix4f& matrix);
  void SetTranslation(const ceVector3f& translation);
  void SetRotation (const ceVector3f& axis, float angle);
  void Translate (const ceVector3f& translation);
  void Rotate (const ceVector3f& axis, float angle);
  ceVector3f GetTranslation () const;
  inline const ceMatrix4f& GetMatrix () const { return _localMatrix; }
  inline const ceMatrix4f& GetMatrixInverted () const { return _localMatrixInverted; }

  virtual void FinishTransformation (bool updateParent = true);


  ceVector3f GetGlobalTranslation () const;
  inline const ceMatrix4f& GetGlobalMatrix () const { return _globalMatrix; }
  inline const ceMatrix4f& GetGlobalMatrixInverted () const { return _globalMatrixInverted; }

  void GlobalLookAt (const ceVector3f& pos, const ceVector3f& up);

  /**
   * @}
   */

  void SetAnimator (iAnimator* animator);
  const iAnimator* GetAnimator() const;
  iAnimator* GetAnimator();



  const ceBoundingBox& GetBoundingBox() const;


  void SetClip (bool clip);
  bool IsClip () const;

  virtual void Update (ceRenderEnvironment& env, iDevice* device);
  inline virtual void FindLights (ceSector *sector) { }
  inline virtual void ClearLights () { }
  inline virtual void TestAndAddLight (ceLight* light) { }
};


/** @} */

#endif /* ! __CE_SCENE_NODE_H__ */
